package com.songshuai.customer.client.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.songshuai.customer.client.controller.BaseController;
import com.songshuai.customer.client.dto.request.login.BindCustomerInfoDto;
import com.songshuai.customer.client.dto.request.login.CustomerIntention;
import com.songshuai.webapi.baseapi.constant.miniprogram.CacheKeys;
import com.songshuai.webapi.baseapi.dto.feign.request.pangu.salemeeting.SendInvitationReqDto;
import com.songshuai.webapi.baseapi.enumerations.ResultStatus;
import com.songshuai.webapi.baseapi.exception.BusinessException;
import com.songshuai.webapi.baseapi.model.custminiprogram.YixueBaseCity;
import com.songshuai.webapi.baseapi.model.sales.CustomerInfo;
import com.songshuai.webapi.baseapi.model.sales.WxPlatform;
import com.songshuai.webapi.baseapi.pojo.QueryResponse;
import com.songshuai.webapi.baseapi.utils.EncryptUtil;
import com.songshuai.webapi.baseapi.utils.RequestParamValidUtil;
import com.songshuai.webapi.common.component.WeChatComponent;
import com.songshuai.webapi.common.httpclient.HttpClientUtil;
import com.songshuai.webapi.common.wechat.WeChatUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author:yubo
 * @Date: 2019/3/14
 */
@Slf4j
@Api("微信平台")
@RestController
@RequestMapping("/api/platform/")
public class WxPlatformController extends BaseController {


    @Value("${customer.pangu.channelId}")
    private String panguChannelId;

    @Autowired
    private WeChatComponent weChatComponent;

    @Value("${customer.mobile.async}")
    private String asyncCustomerUrl;

    @Value("${customer.mobile.solt}")
    private String asyncCustomerSolt;



    @ApiOperation(value = "根据appid获取access_token")
    @PostMapping("getAccessToken")
    public CompletableFuture<QueryResponse> getAccessToken(@RequestParam("appId")String appId){
       return CompletableFuture.supplyAsync(() ->{
           String accessToken = getAccessTokenByAppId(appId);
           return QueryResponse.setResData(accessToken);
       });
    }



    /**
     *1.若该用户是新用户返回未授权状态  不返回token
     *2.若该用户已经绑定过  直接给token   跳过授权页面
     * @param code
     * @param appid
     * @return
     */
    @ApiOperation(value = "根据js_code获取后端程序token")
    @GetMapping("getToken")
    public CompletableFuture<QueryResponse> getToken(@RequestParam("code")String code,@RequestParam("appid")String appid){
        return CompletableFuture.supplyAsync(() ->{
        try {
            WxPlatform wxPlatform = getWxPlatform(appid);
            if (null == wxPlatform || StringUtils.isBlank(wxPlatform.getAppSecret())){
                return new QueryResponse(ResultStatus.UNIDENTIFIABLE_APPID_ERROR);
            }
            JSONObject object = weChatComponent.jscode2session(code,appid,wxPlatform.getAppSecret());
            Integer errcode = object.getInteger("errcode");
            String errmsg = object.getString("errmsg");
            log.info("调用微信获取openId，sessionKey结果："+object.toJSONString());
            if (null == errcode){
                String openid = object.getString("openid");
                String sessionKey = object.getString("session_key");
                Object tokenObject = redisUtil.hget(openid, CacheKeys.OPENID_CUST_KEY);
                String token=null;
                //如果redis存在token直接返回给前端  如果没有则判断数据库是否绑定过，没有绑定不给token  绑定过跟新绑定token
                if(tokenObject!=null){
                    token=(String)tokenObject;
                    //异步初始化数据
                    initUserInfoRedis(token,openid,sessionKey);
                    return  QueryResponse.setResData(token);
                }else{
                    CustomerInfo customerInfo = customerInfoService.selectByEntity(new CustomerInfo() {{
                        setOpenId(openid);
                    }});
                    if(null==customerInfo){
                        return new QueryResponse(ResultStatus.NEED_GET_PERMISSION);
                    }else{
                        token = UUID.randomUUID().toString();
                        pushCustomerTokenToDB(token,openid,customerInfo.getUserId(),sessionKey);//更新数据库openid
                        return QueryResponse.setResData(token);
                    }
                }
            }else {
                return new QueryResponse(ResultStatus.SESSION_KEY_FAILURE);
            }
        } catch (Exception e) {
            log.error("/api/platform/getToken",e);
            throw new BusinessException(ResultStatus.GET_TOKEN_ERROR);
        }
        });
    }




    @ApiOperation(value = "客户端手机号授权保存接口")
    @PostMapping("bindCustomerInfo")
    public CompletableFuture<QueryResponse> bindCustomerInfo(@RequestBody @Valid BindCustomerInfoDto customerInfo, BindingResult result) {
        return CompletableFuture.supplyAsync(() ->{
            try {
                if(result.hasErrors()){
                    return new QueryResponse(ResultStatus.ERROR_INVALID_ARGUMENT.getErrorCode(), RequestParamValidUtil.getBindingResultMessage(result));
                }
                String appid=customerInfo.getAppid();
                String code=customerInfo.getCode();
                String phoneEncryptedData=customerInfo.getPhoneEncryptedData();
                String phoneIv=customerInfo.getPhoneIv();
                WxPlatform wxPlatform = getWxPlatform(appid);
                if (null == wxPlatform || StringUtils.isBlank(wxPlatform.getAppSecret())) {
                    return new QueryResponse(ResultStatus.UNIDENTIFIABLE_APPID_ERROR);
                }
                JSONObject object = weChatComponent.jscode2session(code, appid, wxPlatform.getAppSecret());
                Integer errcode = object.getInteger("errcode");
                String errmsg = object.getString("errmsg");
                log.info("调用微信获取openId，sessionKey结果："+object.toJSONString());
                if (null == errcode) {
                    String openid = object.getString("openid");
                    String sessionKey = object.getString("session_key");
                    String phoneStr = WeChatUtil.decrypt(appid,phoneEncryptedData, sessionKey,phoneIv);
                    log.info("解密到的手机号结果"+phoneStr);
                    if (StringUtils.isNotBlank(phoneStr)) {
                        JSONObject phone = JSON.parseObject(phoneStr);
                        String purePhoneNumber = phone.getString("purePhoneNumber");
                        String token=UUID.randomUUID().toString();
                        //手机号获取成功  1：同步给盘古   2：保存盘古返回的信息同步至数据库  并初始化缓存
                        String s = asyncCustomerInfoToPangu(purePhoneNumber, openid, token, sessionKey, customerInfo);
                        if(StringUtils.isNotBlank(s)){
                            Map<String,String> resultMap=new ConcurrentHashMap<>();
                            resultMap.put("token",token);
                            resultMap.put("isNewCust",s);
                            return QueryResponse.setResData(resultMap);
                        }else{
                            return new QueryResponse(ResultStatus.ERROR_BIND_CUST_INFO);
                        }
                    } else {
                       return new QueryResponse(ResultStatus.SESSION_KEY_FAILURE);
                    }
                } else {
                    return new QueryResponse(ResultStatus.SESSION_KEY_FAILURE);
                }
            } catch (Exception e) {
                log.error("/api/platform/bindCustomerInfo",e);
                throw new BusinessException(ResultStatus.GET_TOKEN_ERROR);
            }
        });
    }



    @ApiOperation(value = "根据父id获取省市区列表")
    @GetMapping("queryAreaByParentId")
    public CompletableFuture<QueryResponse> queryAreaByParentId(@RequestParam("pid") Integer pid) {
        return CompletableFuture.supplyAsync(() ->{
            if(null!=pid){
                QueryResponse<List<YixueBaseCity>> areaList = wxPlatformService.queryAreaByParentId(pid);
                return areaList;
            }else{
                return new QueryResponse(ResultStatus.ERROR_INVALID_ARGUMENT);
            }
        });

    }


    @ApiOperation(value = "保存用户提交营销意向表单数据")
    @PostMapping("saveCustomerIntention")
    public CompletableFuture<QueryResponse> saveCustomerIntention(@RequestBody CustomerIntention customerIntention) {
        String openid = this.getCurrentCustomerOpenid();
        return CompletableFuture.supplyAsync(() ->{
            String mobile=null;
            if(StringUtils.isNotBlank(openid)){
             List<CustomerInfo> customerInfoList=customerInfoService.selectByEntityList(new CustomerInfo(){{
                    setOpenId(openid);
                }});
             if(customerInfoList.size()>0){
                mobile=customerInfoList.get(0).getMobile();
             }
             BindCustomerInfoDto bindCustomerInfoDto=new BindCustomerInfoDto(){{
                setNickName(customerIntention.getTureName());
                setIntentionalCity(customerIntention.getCityCode());
                setIntentionalProvince(customerIntention.getProviceCode());
             }};
                String result = getPanguBindUserResult(mobile,openid, bindCustomerInfoDto);
                log.info("营销钩子 盘古返回信息"+result);
                    return QueryResponse.setResData("");
                } else {
                    return new QueryResponse(ResultStatus.FAIL);
                }
            });

    }





    //客户端第一次登录盘古的同步绑定
    public String asyncCustomerInfoToPangu(String mobile,String openid,String token,String sessionKey,BindCustomerInfoDto custInfo) {
        String asyncCustomer = getPanguBindUserResult(mobile, openid, custInfo);
        if(StringUtils.isNotBlank(asyncCustomer)){
            JSONObject bindCustomerResult = JSON.parseObject(asyncCustomer);
            Integer status=bindCustomerResult.getInteger("status");
            //2:同步修改数据库
            if(0==status){
                JSONObject result = bindCustomerResult.getJSONObject("result");
                String openId = result.getString("OpenId");
                String customGuid = result.getString("CustomGuid");
                String clueGuid = result.getString("ClueGuid");
                String isNewCustomer = String.valueOf(result.getInteger("IsNewCustom"));
                CustomerInfo customerInfo=new CustomerInfo(){{
                    setOpenId(openId);
                    setMobile(mobile);
                    setUserId(customGuid);
                    setCustomerId(clueGuid);
                    setToken(token);
                    setProvince(custInfo.getProvice());
                    setCity(custInfo.getCity());
                    setGender(Integer.parseInt(custInfo.getGender()));
                    setNickName(custInfo.getNickName());
                    setAvatarUrl(custInfo.getAvatarUrl());
                }};
                int i = customerInfoService.insertSelective(customerInfo);
                //3:同步修改Redis
                redisUtil.hset(token, CacheKeys.OPENID, openid, CacheKeys.TIME_OUT_1);
                redisUtil.hset(token,CacheKeys.SESSION_KEY, sessionKey, CacheKeys.TIME_OUT_1);
                redisUtil.hset(openid,CacheKeys.OPENID_CUST_KEY,token,CacheKeys.ONE_DAY);
                redisUtil.hset(token, CacheKeys.PANGU_CUST_ID, customGuid, CacheKeys.TIME_OUT_1);
                return isNewCustomer;
            }
        }
        return null;

    }




    private String getPanguBindUserResult(String mobile, String openid, BindCustomerInfoDto custInfo) {
        //1:同步至盘古
        JSONObject param=new JSONObject();
        param.put("ChannelId",panguChannelId);
        param.put("OpenId",openid);
        param.put("Mobile",mobile);
        param.put("NickName",custInfo.getNickName());
        param.put("Gender",custInfo.getGender());
        param.put("Provice",custInfo.getProvice());
        param.put("City",custInfo.getCity());
        param.put("AvatarUrl",custInfo.getAvatarUrl());
        param.put("IsRecommend",custInfo.getIsRecommend());//是否是推荐客户
        param.put("IntentionalProvince",custInfo.getIntentionalProvince());//意向省份
        param.put("IntentionalCity",custInfo.getIntentionalCity());//意向城市
        param.put("Recommender",custInfo.getRecommender());//推荐人GUID

        Map<String,String> map=new HashMap<>();
        String timstamp=String.valueOf(new Date().getTime());
        map.put("timestamp",timstamp);
        map.put("token", EncryptUtil.md5(asyncCustomerSolt+timstamp));
        StopWatch sw = new StopWatch();
        sw.start();
        String asyncCustomer = HttpClientUtil.doPostHttps(asyncCustomerUrl, param.toJSONString(),map,5000);
        sw.stop();
        log.info("调用盘古客户绑定 POST HTTPS  耗时:"+sw.toString()+" &&& url="+asyncCustomerUrl+"&&& body="+param.toJSONString()+" &&& header="+map.toString()+" &&& 返回结果："+asyncCustomer);
        return asyncCustomer;
    }

    //判断用户登录态  若是以前登陆过并且缓存过期
    //生成新的登录态密钥  并同步改缓存和数据token
    //此方法将用户token更新至数据库和缓存
    @Async
    public void pushCustomerTokenToDB(String token,String openid,String userId,String sessionKey){
        redisUtil.hset(token, CacheKeys.OPENID, openid, CacheKeys.TIME_OUT_1);
        redisUtil.hset(token,CacheKeys.SESSION_KEY, sessionKey, CacheKeys.TIME_OUT_1);
        redisUtil.hset(openid,CacheKeys.OPENID_CUST_KEY,token,CacheKeys.ONE_DAY);
        redisUtil.hset(token, CacheKeys.PANGU_CUST_ID, userId, CacheKeys.TIME_OUT_1);
        CustomerInfo customerInfo=new CustomerInfo(){{
                setToken(token);
                setOpenId(openid);
        }};
        customerInfoService.updateByOpenId(customerInfo);
    }

    //非第一次登录用户  初始化Redis相关值
    @Async
    public void initUserInfoRedis(String token,String openid,String sessionKey){
        Object o = redisUtil.hget(token, CacheKeys.OPENID);
        if(o==null){
            redisUtil.hset(token, CacheKeys.OPENID,openid,CacheKeys.TIME_OUT_1);
            redisUtil.hset(token, CacheKeys.SESSION_KEY,sessionKey,CacheKeys.TIME_OUT_1);
            CustomerInfo customerInfo = customerInfoService.selectByEntity(new CustomerInfo() {{
                setOpenId(openid);
            }});
            redisUtil.hset(token, CacheKeys.PANGU_CUST_ID, customerInfo.getUserId(), CacheKeys.TIME_OUT_1);
        }
    }








}
